﻿using DGIS.GscloudService.IService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DGIS.Model;
using System.Net;
using System.Data.SQLite;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using HtmlAgilityPack;
using System.IO;

namespace DGIS.GscloudService.Service
{
    public class GsCloudService : IGsCloudService
    {
        public bool AddGSDataSets(List<GSDataSet> items)
        {
            bool result = false;

            DataAccessService.IService.ISqliteService sqliteService = new DataAccessService.Service.SqliteService();

            string delSql = "delete from GSDataSet";

            SQLiteConnection conn = sqliteService.GetConn();
            SQLiteTransaction tran = conn.BeginTransaction();

            if (sqliteService.ExcuteSql(conn, tran, delSql))
            {
                foreach (var item in items)
                {
                    if (!sqliteService.AddItem<GSDataSet>(conn, tran, item, "id"))
                    {
                        tran.Rollback();
                        break;
                    }
                }
                tran.Commit();
                result = true;
            }
            else
            {
                tran.Rollback();
            }
            conn.Close();

            return result;
        }

        public List<GSDataSet> GetGSDataSetList()
        {
            DataAccessService.IService.ISqliteService sqliteService = new DataAccessService.Service.SqliteService();
            List<GSDataSet> items = sqliteService.GetList<GSDataSet>("1=1");

            if (!items.Any())
            {
                items = QueryGSDataSetList();
                AddGSDataSets(items);
            }

            List<GSDataSet> groups = items.Where(x => x.pid == "").ToList();
            foreach (var group in groups)
            {
                group.Children = new List<GSDataSet>();
                for (int i = items.Count - 1; i >= 0; i--)
                {
                    GSDataSet item = items[i];
                    if (item.pid == group.dataid)
                    {
                        group.Children.Add(item);
                        items.RemoveAt(i);
                    }
                }
            }
            return groups;
        }

        private string GetDownloadKey(ref CookieContainer cookieContainer)
        {
            string url = "https://www.gscloud.cn/search";
            HttpService httpService = new HttpService();
            string resultStr = httpService.GetHttpWebGetReuslt(url, ref cookieContainer);

            int index = resultStr.IndexOf("?sid=");
            if (index > -1)
            {
                resultStr = resultStr.Substring(index + 1);
                int length= resultStr.IndexOf("' target='_blank'>"); 
                string key = resultStr.Substring(0,length);
                return key;
            }
            else
            {
                return null;
            }

        }

        public List<GSCloud> QueryGSCloudList(string postDataStr, ref CookieContainer cookieContainer)
        {
            string key = GetDownloadKey(ref cookieContainer);
            if (string.IsNullOrEmpty(key))
                return null;

            HttpService httpService = new HttpService();

            string url = "https://www.gscloud.cn/wsd/gscloud_wsd/dataset/p_search";
            string resultStr = httpService.GetHttpWebPostResult(url, postDataStr, ref cookieContainer);
            if (string.IsNullOrEmpty(resultStr))
            {
                return new List<GSCloud>();
            }
            else
            {
                JToken jToken = JProperty.Parse(resultStr)["data"];
                List<GSCloud> items = ParseGSCloud(jToken.ToString());
                foreach (var item in items)
                {
                    item.url = string.Format("https://bjdl.gscloud.cn/sources/download/{0}/{1}?{2}", item.productid, item.dataid, key);
                }

                return items;
            }
        }

        private List<GSCloud> ParseGSCloud(string json)
        {
            List<GSCloud> items = new List<GSCloud>();
            JToken jTokens = JToken.Parse(json);
            foreach (var jToken in jTokens)
            {
                GSCloud item = new GSCloud();
                if (jToken["id"] != null)
                    item.id = jToken["id"].Value<string>() != null ? jToken["id"].Value<int>() : 0;
                if (jToken["dataid"] != null)
                    item.dataid = jToken["dataid"] != null ? jToken["dataid"].Value<string>() : "";
                if (jToken["filesize"] != null)
                    item.filesize = jToken["filesize"].Value<string>() != null ? jToken["filesize"].Value<long>() : 0;
                if (jToken["datadate"] != null)
                    item.datadate = jToken["datadate"].Value<string>() != null ? jToken["datadate"].Value<string>() : "";
                if (jToken["dataexists"] != null)
                    item.dataexists = jToken["dataexists"].Value<string>() != null ? jToken["dataexists"].Value<int>() : 0;
                if (jToken["cloudcover"] != null)
                    item.cloudcover = jToken["cloudcover"].Value<string>() != null ? jToken["cloudcover"].Value<double>() : 0;

                if (jToken["productid"] != null)
                    item.productid = jToken["productid"].Value<string>() != null ? jToken["productid"].Value<string>() : "";
                //if (jToken["ct_lat"] != null)
                //    item.ct_lat = jToken["ct_lat"].Value<string>() != null ? jToken["ct_lat"].Value<double>() : 0;
                //if (jToken["ct_long"] != null)
                //    item.ct_long = jToken["ct_long"].Value<string>() != null ? jToken["ct_long"].Value<double>() : 0;
                //if (jToken["lb_lat"] != null)
                //    item.lb_lat = jToken["lb_lat"].Value<string>() != null ? jToken["lb_lat"].Value<double>() : 0;
                //if (jToken["lb_long"] != null)
                //    item.lb_long = jToken["lb_long"].Value<string>() != null ? jToken["lb_long"].Value<double>() : 0;
                //if (jToken["lt_lat"] != null)
                //    item.lt_lat = jToken["lt_lat"].Value<string>() != null ? jToken["lt_lat"].Value<double>() : 0;
                //if (jToken["lt_long"] != null)
                //    item.lt_long = jToken["lt_long"].Value<string>() != null ? jToken["lt_long"].Value<double>() : 0;
                //if (jToken["rb_lat"] != null)
                //    item.rb_lat = jToken["rb_lat"].Value<string>() != null ? jToken["rb_lat"].Value<double>() : 0;
                //if (jToken["rb_long"] != null)
                //    item.rb_long = jToken["rb_long"].Value<string>() != null ? jToken["rb_long"].Value<double>() : 0;
                //if (jToken["rt_lat"] != null)
                //    item.rt_lat = jToken["rt_lat"].Value<string>() != null ? jToken["rt_lat"].Value<double>() : 0;
                //if (jToken["rt_long"] != null)
                //    item.rt_long = jToken["rt_long"].Value<string>() != null ? jToken["rt_long"].Value<double>() : 0;
                if (jToken["path"] != null)
                    item.path = jToken["path"].Value<string>() != null ? jToken["path"].Value<int>() : 0;
                if (jToken["row"] != null)
                    item.row = jToken["row"].Value<string>() != null ? jToken["row"].Value<int>() : 0;

                JToken coordinates = null;
                if (jToken["the_geom"]["type"].Value<string>() == "Polygon")
                {
                    //var coordinates = the_geom['coordinates'];
                    coordinates = jToken["the_geom"]["coordinates"][0];
                }
                else if (jToken["the_geom"]["type"].Value<string>() == "MultiPolygon")
                {
                    //var coordinates = the_geom['coordinates'];
                    coordinates = jToken["the_geom"]["coordinates"][0][0];
                }

                if (coordinates != null)
                {
                    item.coordinates = new List<double[]>();
                    foreach (var coordinate in coordinates)
                    {
                        double lon = coordinate[0].Value<double>();
                        double lat = coordinate[1].Value<double>();

                        item.coordinates.Add(new double[] { lon, lat });
                    }

                    item.ct_long = item.coordinates.Sum(x => x[0]) / item.coordinates.Count;
                    item.ct_lat = item.coordinates.Sum(x => x[0]) / item.coordinates.Count;

                }
                items.Add(item);
            }

            return items;
        }

        public List<GSDataSet> QueryGSDataSetList()
        {
            List<GSDataSet> items = new List<GSDataSet>();

            string url = "http://www.gscloud.cn/search/datasets";
            CookieContainer cookieContainer = new CookieContainer();
            HttpService httpService = new HttpService();

            string resultStr = httpService.GetHttpWebGetReuslt(url, ref cookieContainer);

            //解析数据
            JToken jTokens = JProperty.Parse(resultStr);
            foreach (JToken jToken in jTokens)
            {
                JToken attrJToken = jToken["attributes"];
                JToken childrenJTokens = jToken["children"];

                string pId = attrJToken["dataid"].ToString();
                items.Add(new GSDataSet()
                {
                    dataid = pId.ToString(),
                    dataname = attrJToken["dataname"].ToString(),
                    pid = "",
                    datatype = ""
                });
                foreach (JToken childJToken in childrenJTokens)
                {
                    attrJToken = childJToken["attributes"];

                    items.Add(new GSDataSet()
                    {
                        dataid = attrJToken["dataid"].ToString(),
                        dataname = attrJToken["dataname"].ToString(),
                        pid = pId
                        //datatype = attrJToken["datatype"].ToString()
                    });
                }
            }

            return items;
        }

        public string QueryImgDownloadUrl(string dataId, string type, ref CookieContainer cookieContainer)
        {
            HttpService httpService = new HttpService();

            string url = string.Format("http://www.gscloud.cn/sources/download/{0}/{1}/bj", type, dataId);

            //先直接获取下载地址
            string resultUrl = httpService.GetHttpWebResponseUrl(url, ref cookieContainer);

            if (!resultUrl.Contains("accounts/login"))
            {
                return resultUrl;
            }
            else
            {

                return QueryImgDownloadUrl(dataId, type, ref cookieContainer);
            }

        }

        private bool Login(string key, string code, ref CookieContainer cookieContainer, out int resultCode)
        {
            //获取本地内置用户名密码
            GSUserService gsUserService = new GSUserService();
            List<GSUser> users = gsUserService.GetGSUserList();
            //随机取出一个用户
            Random random = new Random();
            int index = random.Next(0, users.Count);
            GSUser user = users[index];

            return LoginGSCloud(user.UserName, user.Psw, key, code, ref cookieContainer, out resultCode) != null;
        }

        public Stream GetLoginValidateImg(ref CookieContainer cookieContainer, out string codekey)
        {
            codekey = "";
            string url = "https://www.gscloud.cn/accounts/login_user";
            HttpService httpService = new HttpService();
            string resultStr = httpService.GetHttpWebGetReuslt(url, ref cookieContainer);
            if (resultStr != null)
            {
                //获取id_captcha_0
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(resultStr);

                HtmlNode node = doc.DocumentNode.SelectSingleNode("//*[@id=\"id_captcha_0\"]");
                string code = node.Attributes["value"].Value;
                codekey = code;

                //下载验证码
                url = "http://www.gscloud.cn/captcha/image/" + code + "/";
                //string savePath = string.Format("{0}Cache\\{1}.png", AppDomain.CurrentDomain.BaseDirectory, code);
                return httpService.GetHttpWebGetImg(url, ref cookieContainer);
            }
            else
            {
                return null;
            }
        }

        public bool CheackValidate(string value, string code, ref CookieContainer cookieContainer)
        {
            string url = "http://www.gscloud.cn/accounts/sn_chk";
            string postStr = string.Format("captcha_1={0}&captcha_0={1}", value, code);

            HttpService httpService = new HttpService();
            Dictionary<string, string> headersDic = new Dictionary<string, string>();
            string csrftoken = cookieContainer.GetCookies(new Uri(url))["csrftoken"].Value;
            headersDic.Add("X-CSRFToken", csrftoken);
            headersDic.Add("X-Requested-With", "XMLHttpRequest");

            string resultStr = httpService.GetHttpWebPostResult(url, postStr, headersDic, ref cookieContainer);

            return resultStr == "true";

        }

        public GSUser LoginGSCloud(string userName, string psw, string key, string code, ref CookieContainer cookieContainer, out int resultCode)
        {
            resultCode = 0;

            if (string.IsNullOrEmpty(userName))
            {
                if (Login(key, code, ref cookieContainer, out resultCode))
                {
                    return new GSUser()
                    {
                        Name = "匿名"
                    };
                }
                else
                {
                    return null;
                }
            }
            else
            {

                string public_key =// "-----BEGIN PUBLIC KEY-----\n" +
        @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdU6rOM3AgKIBReK7DsUfW+Qzs
        bpOlughrZltNfUYFsuTBDitdXKC3hp6Vi3pPL1te2JjtoWnX1DemcVxPN5pPwQN+
        vJba+oQzsz5vFFMaKRBSHE14lmVejzzRk61fVWf8LcLC6QUgiM9ZQ3eV3b8HEBkX
        EQ+x97K17Jvqu11j4QIDAQAB";

                //+"-----END PUBLIC KEY-----\n";

                RSACryptoService rsaCryptoService = new RSACryptoService(null, public_key);
                psw = rsaCryptoService.Encrypt(psw);
                psw = System.Web.HttpUtility.UrlEncode(psw, System.Text.Encoding.UTF8);

                HttpService httpService = new HttpService();

                string url = string.Format("https://www.gscloud.cn/accounts/login_view?email={0}&password={1}&haskey={2}&code={3}", userName, psw, key, code);

                Dictionary<string, string> headersDic = new Dictionary<string, string>();
                string csrftoken = cookieContainer.GetCookies(new Uri(url))["csrftoken"].Value;
                headersDic.Add("X-CSRFToken", csrftoken);
                headersDic.Add("X-Requested-With", "XMLHttpRequest");

                //string postStr = string.Format("csrfmiddlewaretoken={2}&next=&userid={0}&password={1}&captcha_1=VGEL&captcha_0={3}", userName, psw, csrftoken, code);
                string resultStr = httpService.GetHttpWebGetReuslt(url, headersDic, ref cookieContainer);

                if (string.IsNullOrEmpty(resultStr))
                {
                    return null;
                }
                else
                {
                    JToken jToken = JProperty.Parse(resultStr)["code"];
                    resultCode = jToken.Value<int>();
                    if (resultCode == 1)
                    {
                        //获取用户名
                        return new GSUser()
                        {
                            Name = GetLoginUserName(ref cookieContainer)
                        };
                    }
                    else
                    {
                        return null;
                    }
                }
            }
        }

        private string GetLoginUserName(ref CookieContainer cookieContainer)
        {
            string url = "http://www.gscloud.cn/accounts/userinfo";
            HttpService httpService = new HttpService();
            string resultStr = httpService.GetHttpWebGetReuslt(url, ref cookieContainer);

            HtmlDocument htmlDocument = new HtmlDocument();
            htmlDocument.LoadHtml(resultStr);

            HtmlNode nameNode = htmlDocument.DocumentNode.SelectSingleNode("//input[@id='username']");

            return nameNode.Attributes["value"].Value;
        }
    }
}
